package com.weilx959.spt.core.component;

import com.jfoenix.controls.JFXCheckBox;
import com.weilx959.spt.core.constants.CommonConstants;
import com.weilx959.spt.core.utils.FXMLUtil;
import com.weilx959.spt.core.utils.Try;
import javafx.beans.DefaultProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.util.Pair;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.collections4.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 多选框表单项控件
 *
 * @param <T> 值类型
 * @author weilx
 * @since 2024年6月5日
 */
@DefaultProperty("options")
public class CheckBoxFormItemControl<T> extends ParentFormItemControl<List<T>> {
    private static final String XML = "/assets/fxml/component/check-box-form-control.fxml";

    @FXML
    private Label labelControl;

    @FXML
    private HBox checkBoxesBox;

    private ObjectProperty<ObservableList<Pair<String, T>>> options;

    @Getter
    @Setter
    private boolean required;

    public CheckBoxFormItemControl() {
        super();
        initialize();
    }

    @Override
    public boolean isModified() {
        if (CollectionUtils.isEmpty(getValue()) && CollectionUtils.isEmpty(oldValue)) { // 同时为空
            return false;
        }
        if (CollectionUtils.isEmpty(getValue()) || CollectionUtils.isEmpty(oldValue)) { // 有一个为空
            return true;
        }
        return !CollectionUtils.isEqualCollection(getValue(), oldValue); // 集合不相等
    }

    @Override
    public ObjectProperty<List<T>> valueProperty() {
        if (Objects.isNull(value)) {
            value = new SimpleObjectProperty<>(this, "value", new ArrayList<>());
        }
        return value;
    }

    @Override
    public Try<String> validate() {
        return Try.of(() -> {
            if (required && CollectionUtils.isEmpty(getValue())) {
                throw new IllegalArgumentException(getLabel() + "不能为空！");
            }
        });
    }

    @Override
    public void reset() {
        if (Objects.isNull(oldValue)) {
            setValue(new ArrayList<>());
        } else {
            setValue(new ArrayList<>(oldValue));
        }
        super.pseudoClassStateChanged(PSEUDO_CLASS_MODIFIED, false);
    }

    @Override
    public void submit() {
        List<T> v = getValue();

        if (Objects.isNull(v)) {
            oldValue = new ArrayList<>();
        } else {
            oldValue = new ArrayList<>(v);
        }
        super.pseudoClassStateChanged(PSEUDO_CLASS_MODIFIED, false);
    }

    public ObjectProperty<ObservableList<Pair<String, T>>> optionsProperty() {
        if (Objects.isNull(options)) {
            options = new SimpleObjectProperty<>(this, "options", FXCollections.observableArrayList());
        }
        return options;
    }

    public void setOptions(ObservableList<Pair<String, T>> options) {
        optionsProperty().set(options);
    }

    public ObservableList<Pair<String, T>> getOptions() {
        return optionsProperty().get();
    }

    private void initialize() {
        // load
        FXMLUtil.loadControl(this, XML);
        // check boxes
        this.loadCheckBoxes(getOptions());
        // options listener
        optionsProperty().addListener((observable, oldValue, newValue) -> this.loadCheckBoxes(newValue));
        getOptions().addListener((ListChangeListener<Pair<String, T>>) c -> this.loadCheckBoxes(getOptions()));
        // value listener
        valueProperty().addListener((observable, oldValue, newValue) -> {
            if (CollectionUtils.isEmpty(checkBoxesBox.getChildren())) {
                return;
            }
            for (Node child : checkBoxesBox.getChildren()) {
                JFXCheckBox checkBox = (JFXCheckBox) child;
                checkBox.setSelected(CollectionUtils.containsAny(newValue, checkBox.getUserData()));
            }
        });
    }

    /**
     * 加载单选按钮
     *
     * @param options 选项
     */
    private void loadCheckBoxes(List<Pair<String, T>> options) {
        checkBoxesBox.getChildren().clear();
        if (CollectionUtils.isEmpty(options)) {
            return;
        }
        for (Pair<String, T> option : options) {
            JFXCheckBox checkBox = new JFXCheckBox(option.getKey());
            checkBox.setUserData(option.getValue());
            checkBox.getStyleClass().add(CommonConstants.Style.CHECK_BOX);
            checkBox.setSelected(CollectionUtils.containsAny(getValue(), option.getValue()));
            checkBox.selectedProperty().addListener((observable, oldValue, newValue) -> {
                if (Objects.equals(oldValue, newValue)) {
                    return;
                }
                if (Boolean.TRUE.equals(newValue)) {
                    valueProperty().get().add(option.getValue());
                } else {
                    valueProperty().get().remove(option.getValue());
                }
                super.pseudoClassStateChanged(PSEUDO_CLASS_MODIFIED, isModified());
            });
            checkBoxesBox.getChildren().add(checkBox);
        }
    }

    // builder
    public static <T> CheckBoxFormItemControlBuilder<T> builder() {
        return new CheckBoxFormItemControlBuilder<>();
    }

    public static class CheckBoxFormItemControlBuilder<T>
        extends ParentFormItemControlBuilder<List<T>, CheckBoxFormItemControl<T>, CheckBoxFormItemControlBuilder<T>> {
        private ObservableList<Pair<String, T>> options;
        private boolean required;

        public CheckBoxFormItemControlBuilder<T> addValue(T value) {
            if (Objects.isNull(this.value)) {
                this.value = new ArrayList<>();
            }
            this.value.add(value);
            return this;
        }

        public CheckBoxFormItemControlBuilder<T> options(ObservableList<Pair<String, T>> options) {
            this.options = options;
            return this;
        }

        public CheckBoxFormItemControlBuilder<T> option(Pair<String, T> option) {
            if (Objects.isNull(options)) {
                options = FXCollections.observableArrayList();
            }
            options.add(option);
            return this;
        }

        public CheckBoxFormItemControlBuilder<T> option(String key, T value) {
            if (Objects.isNull(options)) {
                options = FXCollections.observableArrayList();
            }
            options.add(new Pair<>(key, value));
            return this;
        }

        public CheckBoxFormItemControlBuilder<T> required(boolean required) {
            this.required = required;
            return this;
        }

        @Override
        public CheckBoxFormItemControl<T> build() {
            CheckBoxFormItemControl<T> control = super.build();
            control.setOldValue(new ArrayList<>(value));
            control.setValue(value);
            control.setOptions(options);
            control.setRequired(required);
            return control;
        }

        @Override
        protected CheckBoxFormItemControl<T> newFormItemControl() {
            return new CheckBoxFormItemControl<>();
        }

        @Override
        protected CheckBoxFormItemControlBuilder<T> self() {
            return this;
        }
    }
}
